#ifndef __SELECTSERVER_HPP__
#define __SELECTSERVER_HPP__

#include "Sock.hpp"

#define NUM (sizeof(fd_set) * 8)
#define FD_NONE -1

class SelectServer {
public:
  SelectServer(uint16_t port = 8080)
    :_port(port)
  {
    _listenSock = Socket::SockInit();
    
    Socket::SockBind(_listenSock, _port);
    Socket::SockListen(_listenSock);
    for(int i = 0; i < (int)NUM; i++) {
      _rdArray[i] = FD_NONE;
    }
    _rdArray[0] = _listenSock;
  }

  void Run() {
    while(1) {
      Showrds();

      fd_set rfds;
      FD_ZERO(&rfds);

      int maxfd = _listenSock;
      for(int i = 0; i < (int)NUM; i++) {
        if(_rdArray[i] == FD_NONE) {
          continue;
        }

        maxfd = std::max(maxfd, _rdArray[i]);
        FD_SET(_rdArray[i], &rfds);
      }

      int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);

      switch(n) {
        case 0:
          LogMessage(DEBUG, _F, _L, "time out");
          break;
        case -1:
          LogMessage(ERROR, _F, _L, "select err,errno::%d, strerror::", errno, strerror(errno));
          break;
        default:
          LogMessage(NORMAL, _F, _L, "fd is ready");
          EventHandler(rfds);
          break;
      }
    }
  }
  
  void EventHandler(fd_set &rfds) {
    for(int i = 0; i < int(NUM); i++) {
      if(_rdArray[i] == FD_NONE) {
        continue;
      }
      
      if(FD_ISSET(_rdArray[i], &rfds)) {
        if(i == 0) {
          Accepter();
        } else {
          Reader(i);
        }
      }
    }
  }

  void Accepter() {
    std::string clientIP;
    uint16_t clientPort;

    int sock = Socket::SockAccept(_listenSock, clientIP, clientPort);
    int pos = 1;
    for(; pos < int(NUM); pos++) {
      if(_rdArray[pos] == FD_NONE) {
        break;
      }
    }

    if(pos == NUM) {
      std::cout << "文件描述符集已满, 无法继续接收连接" << std::endl;
      close(sock);
    } else {
      std::cout << "new fd::" << sock << std::endl;
      _rdArray[pos] = sock;
    }
  }

  void Reader(int pos) {
    char buff[1024] = {0};
    ssize_t res = read(_rdArray[pos], buff, sizeof(buff) - 1);
    if(res > 0) {
      buff[res - 1] = 0;
      printf("get client[%d] message # %s\n", _rdArray[pos], buff);
    } else if(res == 0) { // 对端关闭连接
      printf("client[%d] closed,me too\n", _rdArray[pos]);
      close(_rdArray[pos]);

      _rdArray[pos] = FD_NONE;

    } else {  // read出错 
      printf("read error,close client[%d]\n", _rdArray[pos]);
      std::cout << "read err ::" << errno << strerror(errno) << std::endl;
      close(_rdArray[pos]);
      // 记得要把数组中对应位置置为FD_NONE
      _rdArray[pos] = FD_NONE;
    }
  }

  void Showrds() {
    std::cout << "rds::";
    for(auto x : _rdArray) {
      if(x == FD_NONE) {
        continue;
      }
      std::cout << x << ' ';
    }
    std::cout << std::endl;
  }

  ~SelectServer() {
    if(_listenSock >= 0) {
      close(_listenSock);
    }
  }
private:
  int _listenSock;
  uint16_t _port;
  int _rdArray[NUM];
};


#endif
